package util.bio.parsers;
import java.io.*;
import util.bio.annotation.*;
import util.gen.*;
import java.util.*;


/**Parses a UCSC gene model table file (either refSeq or refFlat), use table options for #hg17.refGene.name	hg17.refLink.product	hg17.geneName.name	hg17.refSeqSummary.summary... example:
 *#refGene.name	refGene.chrom	refGene.strand	refGene.txStart	refGene.txEnd	refGene.cdsStart	refGene.cdsEnd	refGene.exonCount	refGene.exonStarts	refGene.exonEnds	refLink.product	geneName.name	refSeqSummary.summary
 *NM_198576	chr1	+	995569	1031415	995619	1030284	36	995569,997647,1010723,1016111,1016522,1016827,1017258,1018541,1018840,1019125,1019411,1019636,1020463,1020661,1021035,1021266,1021462,1021699,1022122,1022629,1022875,1023078,1023314,1024169,1024538,1024868,1025205,1025535,1025729,1026028,1026555,1026755,1027030,1029055,1029750,1030126,	995820,997909,1010771,1016327,1016747,1017052,1017465,1018760,1019035,1019326,1019560,1019742,1020580,1020826,1021179,1021391,1021568,1022038,1022260,1022757,1022990,1023198,1023668,1024362,1024754,1025098,1025340,1025632,1025894,1026140,1026672,1026948,1027118,1029280,1029854,1031415,	agrin	AGRIN	Agrin is a neuronal aggregating factor that induces the aggregation of ... * */
public class UCSCGeneModelTableReader {
	
	//fields
	private UCSCGeneLine[] geneLines = null;
	private HashMap<String,UCSCGeneLine[]> chromSpecificGeneLines = null;
	
	//test main
	public static void main(String[] args){
		//(new UCSCGeneModelTableReader (new File (args[0]), 1)).readOutHash();
		UCSCGeneModelTableReader reader = new UCSCGeneModelTableReader (new File (args[0]), 1);
		reader.splitByChromosome();
		reader.printAllExons(225);
	}
	
	//constructors
	/**@param numToSubtractFromEnd - UCSC uses interbase numbering, to get to end inclusive numbering 
	 * you must subtract one from the ends of everything, thus set to 1.*/
	public UCSCGeneModelTableReader (File file, int numToSubtractFromEnd){
		parseGeneTableFile(file, numToSubtractFromEnd);
	}
	public UCSCGeneModelTableReader(){}
	
	/**Prints all exons to standard out.  Subtracts bpEndMod from start, adds it to end.*/
	public void printAllExons (int bpEndMod){
		Iterator it = chromSpecificGeneLines.keySet().iterator();
		while (it.hasNext()){
			String chrom = (String) it.next();
			UCSCGeneLine[] sub = (UCSCGeneLine[]) chromSpecificGeneLines.get(chrom);
			for (int i=0; i< sub.length; i++){
				ExonIntron[] exons = sub[i].getExons();
				for (int j=0; j< exons.length; j++){
					int start = exons[j].getStart() - bpEndMod;
					if (start < 0) start = 0;
					int end = exons[j].getEnd()+ bpEndMod;
					System.out.println(chrom+"\t"+start+"\t"+end);
				}
			}
			
		}
	}
	/**To test your hash.*/
	public void readOutHash(){
		Iterator it = chromSpecificGeneLines.keySet().iterator();
		while (it.hasNext()){
			String chrom = (String) it.next();
			System.out.println(chrom);
			UCSCGeneLine[] sub = (UCSCGeneLine[]) chromSpecificGeneLines.get(chrom);
			System.out.println(sub.length + " "+ sub[0]);
		}
	}
	
	/**Splits a UCSCGeneLine[] by chromosome into a HashMap of chromosome:UCSCGeneLine[].*/
	public void splitByChromosome(){
		Arrays.sort(geneLines, new UCSCGeneLineComparator());
		chromSpecificGeneLines = new HashMap();
		ArrayList al = new ArrayList();
		String currChrom = geneLines[0].getChrom();
		for (int i=0; i< geneLines.length; i++){
			if (geneLines[i].getChrom().equals(currChrom) == false){
				UCSCGeneLine[] sub = new UCSCGeneLine[al.size()];
				al.toArray(sub);
				chromSpecificGeneLines.put(currChrom, sub);
				al.clear();
				currChrom = geneLines[i].getChrom();
			}
			al.add(geneLines[i]);
		}
		//add last to hash
		UCSCGeneLine[] sub = new UCSCGeneLine[al.size()];
		al.toArray(sub);
		chromSpecificGeneLines.put(currChrom, sub);
		al.clear();
	}

	/**@param numToSubtractFromEnd - UCSC uses interbase numbering, to get to end inclusive numbering 
	 * you must subtract one from the ends of everything, thus set to 1.*/
	public void parseGeneTableFile(File file, int numToSubtractFromEnd){
		BufferedReader in;
		try{
			in = new BufferedReader (new FileReader (file));
			String line;
			ArrayList al = new ArrayList();
			boolean displayNamePresent = false;
			boolean checkForDisplayName = true;
			while ((line = in.readLine()) != null){
				line = line.trim();
				if (line.length() == 0 || line.startsWith("#")) continue;
				String[] tokens = line.split("\\t");
				//check for a display name?
				if (checkForDisplayName){
					//look for +,-,or . in tokens[3]
					if (tokens[3].matches("[+-\\.]")) {
						displayNamePresent = true;						
					}
					checkForDisplayName = false;
				}
				if (tokens.length < 10) Misc.printExit("\nError: problem parsing gene table file with line -> "+line);
				al.add(new UCSCGeneLine(tokens, numToSubtractFromEnd,displayNamePresent));
			}
			in.close();
			geneLines = new UCSCGeneLine[al.size()];
			al.toArray(geneLines);
		
		} catch (IOException e){
			e.printStackTrace();
		}
	}

	public HashMap<String,UCSCGeneLine[]> getChromSpecificGeneLines() {
		if (chromSpecificGeneLines == null) splitByChromosome();
		return chromSpecificGeneLines;
	}

	public UCSCGeneLine[] getGeneLines() {
		return geneLines;
	}
	
	public boolean checkStartStopOrder(){
		for (int i=0; i<geneLines.length; i++){
			if (geneLines[i].getTxEnd() < geneLines[i].getTxStart()) return false;
		}
		return true;
	}

	public void setGeneLines(UCSCGeneLine[] geneLines) {
		this.geneLines = geneLines;
	}
	
}
